﻿using System;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using DotNetOpenAuth.OpenId.RelyingParty;
using Mvc.Mailer;
using viBook.Common;
using viBook.Mailers;
using viBook.Models;

namespace viBook.Controllers
{
    public class AccountController : BaseController
    {
        #region Constructors and Repository vars

        private readonly OpenIdRelyingParty _openId;
        private readonly IUserRepository _userRepository;
        private readonly IUserMailer _userMailer;

        public AccountController()
            : this(new UserRepository())
        {

        }

        public AccountController(IUserRepository userRepository)
        {
            _openId = new OpenIdRelyingParty();
            _userMailer = new UserMailer();
            _userRepository = userRepository;
        }

        #endregion

        [ValidateInput(false)]
        public ActionResult Authenticate(string returnUrl)
        {
            var response = _openId.GetResponse();
            if (response == null)
            {

                //Let us submit the request to OpenID provider
                Identifier id;
                if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                {
                    try
                    {
                        var request = _openId.CreateRequest(Request.Form["openid_identifier"]);
                        var fetch = new FetchRequest();
                        fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
                        request.AddExtension(fetch);
                        return request.RedirectingResponse.AsActionResult();
                    }
                    catch (ProtocolException ex)
                    {
                        ViewBag.Message = ex.Message;
                        return View("LogOn");
                    }
                }

                ViewBag.Message = "Invalid identifier";
                return View("LogOn");
            }

            //Let us check the response
            switch (response.Status)
            {

                case AuthenticationStatus.Authenticated:
                    var fetch = response.GetExtension<FetchResponse>();
                    string email = "";
                    if (fetch != null)
                    {
                        email = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
                    }
                    _userRepository.CreateExternalUser(email);
                    FormsAuthentication.SetAuthCookie(email, false);
                    return RedirectToAction("Index", "Home");

                case AuthenticationStatus.Canceled:
                    ViewBag.Message = "Canceled at provider";
                    return View("LogOn");
                case AuthenticationStatus.Failed:
                    ViewBag.Message = response.Exception.Message;
                    return View("LogOn");
            }

            return new EmptyResult();
        }

        [Authorize]
        public ActionResult Index()
        {
            var user = _userRepository.Find(ExtendedIdentity.Id);
            return View(user);
        }

        public ActionResult LogOn()
        {
            return View();
        }

        [HttpPost]
        public ActionResult LogOn(LogOnModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                User user;
                if (_userRepository.ValidateUser(model.UserName, model.Password, out user))
                {
                    FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                    SessionPersiter.User = user;
                    if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
                        && !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
                    {
                        return Redirect(returnUrl);
                    }
                    return user.Status.Equals(Constant.StatusCreated) ? RedirectToAction("RequireActivation") : RedirectToAction("Index", "Home");
                }
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
            return View(model);
        }

        public ActionResult LogOff()
        {
            FormsAuthentication.SignOut();
            return RedirectToAction("Index", "Home");
        }

        public ActionResult Register()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                var result = new User();
                var realHash = Request.Form["realHash"];
                var realInput = UserRepository.RpHash(model.RealPerson);
                //                if (!realInput.Equals(realHash))
                //                {
                //                    ModelState.AddModelError("RealPerson", "You must type the letters you see.");
                //                }
                if (ModelState.IsValid)
                {
                    try
                    {
                        result = _userRepository.CreateInternalUser(model.UserName, model.Password, model.Email);
                    }
                    catch (ArgumentException e)
                    {
                        ModelState.AddModelError(e.ParamName, e.Message);
                    }

                    if (result != null)
                    {
                        //                        _userMailer.Activate(result).Send();
                        FormsAuthentication.SetAuthCookie(model.UserName, false);
                        return RedirectToAction("RequireActivation");
                    }
                }
            }
            return View(model);
        }

        public ActionResult Activate()
        {
            string userId = Request.QueryString["userid"];
            string validationCode = Request.QueryString["code"];
            if (!String.IsNullOrEmpty(userId) && !String.IsNullOrEmpty(validationCode))
            {
                try
                {
                    int id = Int32.Parse(userId);
                    if (_userRepository.ValidateActivationCode(id, validationCode))
                    {
                        return RedirectToAction("ActivateSuccess", "Account");
                    }
                }
                catch (Exception)
                {
                    return View();
                }
            }
            return View();
        }

        public ActionResult Reactivate()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Reactivate(RequireEmailModel model)
        {
            var realHash = Request.Form["realHash"];
            var realInput = UserRepository.RpHash(model.RealPerson);
            if (!realInput.Equals(realHash))
            {
                ModelState.AddModelError("RealPerson", "You must type the letters you see.");
            }
            if (ModelState.IsValid)
            {
                var user = _userRepository.Reactivate(model.Email);
                if (user != null)
                {
                    _userMailer.Activate(user).Send();
                    return RedirectToAction("ActivationSent", "Account");
                }
            }
            return View(model);
        }

        [Authorize]
        public ActionResult ChangePassword()
        {
            return View();
        }

        [Authorize, HttpPost]
        public ActionResult ChangePassword(ChangePasswordModel model)
        {
            if (ModelState.IsValid)
            {
                // ChangePassword will throw an exception rather
                // than return false in certain failure scenarios.
                bool changePasswordSucceeded;
                try
                {
                    var currentUser = Membership.GetUser(User.Identity.Name, true);
                    changePasswordSucceeded = currentUser.ChangePassword(model.OldPassword, model.NewPassword);
                }
                catch (Exception)
                {
                    changePasswordSucceeded = false;
                }

                if (changePasswordSucceeded)
                {
                    return RedirectToAction("ChangePasswordSuccess");
                }
                else
                {
                    ModelState.AddModelError("", "The current password is incorrect or the new password is invalid.");
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

        public ActionResult RequestResetPassword()
        {
            return View();
        }

        [HttpPost]
        public ActionResult RequestResetPassword(RequireEmailModel model)
        {
            var realHash = Request.Form["realHash"];
            var realInput = UserRepository.RpHash(model.RealPerson);
            if (!realInput.Equals(realHash))
            {
                ModelState.AddModelError("RealPerson", "You must type the letters you see.");
            }
            if (ModelState.IsValid)
            {
                var user = _userRepository.RequestResetPassword(model.Email);
                if (user != null)
                {
                    _userMailer.ResetPassword(user).Send();
                    return RedirectToAction("ResetPasswordSent");
                }
            }
            return View(model);
        }

        public ActionResult ResetPassword()
        {
            string userId = Request.QueryString["userid"];
            if (!String.IsNullOrEmpty(userId))
            {
                try
                {
                    var user = _userRepository.Find(Int32.Parse(userId));
                    ViewBag.Username = user.Username;
                }
                catch (Exception)
                {
                    return RedirectToAction("Index", "Home");
                }

            }
            return View();
        }

        [HttpPost]
        public ActionResult ResetPassword(ResetPasswordModel model)
        {
            string userId = Request.QueryString["userid"];
            string validationCode = Request.QueryString["code"];
            try
            {
                int id = Int32.Parse(userId);
                if (_userRepository.ValidateNewPassword(id, validationCode, model.NewPassword))
                {
                    return RedirectToAction("ResetPasswordSuccess");
                }
            }
            catch (Exception)
            {
                return View(model);
            }
            return View(model);
        }

        public ActionResult ChangePasswordSuccess()
        {
            return View();
        }

        public ActionResult RequireActivation()
        {
            return View();
        }

        public ActionResult ActivationSent()
        {
            return View();
        }

        public ActionResult ActivateSuccess()
        {
            return View();
        }

        public ActionResult ResetPasswordSent()
        {
            return View();
        }

        public ActionResult ResetPasswordSuccess()
        {
            return View();
        }
    }
}
